<?php 
class PaymentOfflineCC extends Payment {
	function __construct(&$locator) {
		$this->address  =& $locator->get('address');
		$this->config   =& $locator->get('config');
		$this->database =& $locator->get('database');
		$this->language =& $locator->get('language');
		$this->mail     =& $locator->get('mail');
		$this->order    =& $locator->get('order');
		$this->request  =& $locator->get('request');
		$this->response =& $locator->get('response');
		$this->session  =& $locator->get('session');
		$this->url      =& $locator->get('url');	    
		
		$this->language->load('extension/payment/offline_cc.php');
  	}
  
	function getTitle() {
		return $this->language->get('text_offline_cc_title');
  	}
   
  	function getMethod() {
		if ($this->config->get('offline_cc_status')) {
      		if (!$this->config->get('offline_cc_geo_zone_id')) {
        		$status = true;
      		} elseif ($this->database->getRows("select * from zone_to_geo_zone where geo_zone_id = '" . (int)$this->config->get('offline_cc_geo_zone_id') . "' and country_id = '" . (int)$this->address->getCountryId($this->session->get('payment_address_id')) . "' and (zone_id = '" . (int)$this->address->getZoneId($this->session->get('payment_address_id')) . "' or zone_id = '0')")) {
        		$status = true;
      		} else {
        		$status = false;
      		}
		} else {
			$status = false;
		}
		
		$method_data = array();
	
		if ($status) {  
      		$method_data = array( 
        		'id'         => 'offline_cc',
        		'title'      => $this->language->get('text_offline_cc_title'),
				'sort_order' => $this->config->get('offline_cc_sort_order')
      		);
    	}
   
    	return $method_data;
  	}

  	// create the credit card entry form on the checkout_confirm page
  	function fields() {

        $output = '';
        $output .= '<div class="offline_cc_form" style="border: 1px solid #EEEEEE; margin-bottom: 10px; padding: 2px; background-color: #eeeeee;">';
        $output .= '<font size="2pt"><strong>' . $this->language->get('text_creditcard') . '</strong></font>' . "\n";
        $output .= '<table>' . "\n";
        $output .= '<tr><td><span class="required">*</span>&nbsp;' . $this->language->get('entry_cc_type') . '</td><td><select name="cc_type">';
        $output .= '<option value="none"></option>';
        $output .= '<option value="visa">VISA</option>';
        $output .= '<option value="mastercard">MC</option>';
        $output .= '<option value="amex">AMEX</option>';
        $output .= '<option value="disc">DISC</option>';
        $output .= '<option value="diner">DINER</option>';
        $output .= '</select></td></tr>' . "\n";
		$output .= '<tr><td><span class="required">*</span>&nbsp;' . $this->language->get('entry_cc_name') . '</td><td><input type="text" name="cc_name" value="'.$this->session->get('cc_name').'"></td></tr>' . "\n";
        $output .= '<tr><td><span class="required">*</span>&nbsp;' . $this->language->get('entry_cc_number') . '</td><td><input type="text" name="cc_number" value="'.$this->session->get('cc_number').'"></td></tr>' . "\n";
        $output .= '<tr><td><span class="required">*</span>&nbsp;' . $this->language->get('entry_cc_expire') . '</td><td><input type="text" name="cc_month" value="'.$this->session->get('cc_month').'" size="3" maxlength="2"> / <input type="text" name="cc_year" value="'.$this->session->get('cc_year').'" size="3" maxlength="2"></td></tr>' . "\n";
        $output .= '<tr><td><span class="required">*</span>&nbsp;' . $this->language->get('entry_cc_cvv') . '</td><td><input type="text" name="cc_cvv" value="'.$this->session->get('cc_cvv').'" size="3"></td></tr>' . "\n";
        $output .= '</table>';
        $output .= '</div>';
       
	    $this->session->delete('cc_type');
	    $this->session->delete('cc_name');
	    $this->session->delete('cc_number');
        $this->session->delete('cc_month');
        $this->session->delete('cc_year');
        $this->session->delete('cc_cvv'); 

        return $output;
        
  	}
  	
  	function getActionUrl() {
    	return $this->url->ssl('checkout_process');
	}

  	function process() {
		if ($this->request->isPost()) {  
			if (!$this->validateForm()) {
            	if (!empty($this->errors)) {
		        	$this->session->set('error', $this->errors[0]);
                }
                $this->response->redirect($this->url->rawssl('checkout_confirm',false));
            }
            
            $ref_id = $this->order->getReference();
	    	$ccType = $this->request->get('cc_type', 'post');
	    	$ccName = $this->request->get('cc_name', 'post');
        	$ccNumber = preg_replace('/[^0-9 -]/', '', $this->request->get('cc_number', 'post')); // strip non numerics from the text but leave spaces for the moment.
        	$ccMonth = $this->request->get('cc_month', 'post');
        	$ccYear = $this->request->get('cc_year', 'post');
        	$ccCVV = $this->request->get('cc_cvv', 'post'); 
        	
			$this->mail->setTo($this->config->get('config_email'));
			$this->mail->setFrom($this->config->get('config_email'));
	    	$this->mail->setSender($this->config->get('config_store'));
	    	$this->mail->setSubject($this->language->get('email_subject', $ref_id));
	    	$this->mail->setText($this->language->get('email_message', $ref_id, $ccType,  $ccName, $ccNumber, $ccMonth .'/'. $ccYear, $ccCVV));
	    	$this->mail->send();
	    				
			$this->order->load($this->order->getReference());
			$this->order->process();
			
			$this->session->delete('cc_type');
	    	$this->session->delete('cc_name');
	    	$this->session->delete('cc_number');
        	$this->session->delete('cc_month');
        	$this->session->delete('cc_year');
        	$this->session->delete('cc_cvv'); 
			
			// Update DB Order with CC Data
			$this->database->query("UPDATE `order` SET cc_type = '" . $ccType . "', cc_name = '" . $ccName . "', cc_number = '" . $ccNumber . "', cc_exp = '" . $ccMonth . "/" . $ccYear . "', cc_cvv = '" . $ccCVV . "' where reference = '" . $ref_id . "'");
		}
  	}
  	
  	
  	// Pre-Validates user input from the form before attempting to send.
    private function validateForm() {
        
        // Save the fields to the session for repopulation
        $this->session->set('cc_type', $this->request->gethtml('cc_type', 'post'));
        $this->session->set('cc_name', $this->request->gethtml('cc_name', 'post'));
        $this->session->set('cc_number', $this->request->gethtml('cc_number', 'post'));
        $this->session->set('cc_month', $this->request->gethtml('cc_month', 'post'));
        $this->session->set('cc_year', $this->request->gethtml('cc_year', 'post'));
        $this->session->set('cc_cvv', $this->request->gethtml('cc_cvv', 'post'));
        
        $this->errors = array();
        $ccType = $this->request->get('cc_type', 'post'); 
        $ccName = $this->request->get('cc_name', 'post'); 
        $ccNumber = preg_replace('/[^0-9 -]/', '', $this->request->get('cc_number', 'post')); // strip non numerics from the text but leave spaces for the moment.
        $ccMonth = $this->request->get('cc_month', 'post');
        $ccYear = $this->request->get('cc_year', 'post');
        $ccCVV = $this->request->get('cc_cvv', 'post'); 

        if (strcmp($ccType, 'none') == 0) {
             $this->errors[] = $this->language->get('error_cc_type_missing');
		}
        
        if (strlen($ccName) == 0) {
            $this->errors[] = $this->language->get('error_cc_name_missing');
        }
        
        if (strlen($ccNumber) == 0) {
            $this->errors[] = $this->language->get('error_cc_number_missing');
        } else if (strlen($ccNumber) <> strlen($this->request->get('cc_number', 'post'))) {
            $this->errors[] = $this->language->get('error_cc_number_not_numeric');
        }

        if (strlen($ccMonth) == 0) {
            $this->errors[] = $this->language->get('error_cc_month_missing');
        }
                            
        if (strlen($ccYear) == 0) {
            $this->errors[] = $this->language->get('error_cc_year_missing');
        }
                            
        if (strlen($ccCVV) == 0) {
            $this->errors[] = $this->language->get('error_cc_cvv_missing');
        }
        
        //  No point to continue validating if we already have an error.
        if (count($this->errors) > 0) {
            return false;
        }
                       
        //  now we remove harmless spaces or dashes from the credit card number so that we can test it as a number.
        $ccNumber = ereg_replace('[ -]', '', $ccNumber);
        
        //  and remove all non numerics from the following and validate them.
        $ccMonth = ereg_replace('[^0-9]', '', $ccMonth);
        $ccYear = ereg_replace('[^0-9]', '', $ccYear);
 
        if (strlen($ccMonth) <> strlen($this->request->get('cc_month', 'post'))) {
            $this->errors[] = $this->language->get('error_cc_month_not_numeric');       
        }
        if (strlen($ccYear) <> strlen($this->request->get('cc_year', 'post'))) {
            $this->errors[] = $this->language->get('error_cc_year_not_numeric');       
        }

        //  No point to continue validating if we already have an error.
        if (count($this->errors) > 0) {
            return false;
        }
            
        //  Validate credit card number by common algorithm
        $cardNumber = strrev($ccNumber);
        $numSum = 0;
        for($i = 0; $i < strlen($cardNumber); $i++) {
            $currentNum = substr($cardNumber, $i, 1);

            // Double every second digit
            if ($i % 2 == 1) {
                $currentNum *= 2;       
            }

            // Add digits of 2-digit numbers together
            if ($currentNum > 9) {
                $firstNum = $currentNum % 10;
                $secondNum = ($currentNum - $firstNum) / 10;
                $currentNum = $firstNum + $secondNum;
            }
            $numSum += $currentNum;
        }
        if ($numSum % 10 != 0) {
            $this->errors[] = $this->language->get('error_cc_number_invalid');
            return false;            
        }
 
        
        //  Validate the number(s) match the card type  
        switch ($ccType) {
            case 'mastercard':
                if (!(ereg("^5[1-5][0-9]{14}$", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type'); 
                if (!(ereg("^[0-9][0-9][0-9]$", $ccCVV)))
                    $this->errors[] = $this->language->get('error_mastercard_cvv');   
                break;
            case 'visa':
                if (!(ereg("^4[0-9]{12}([0-9]{3})?$", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type'); 
                if (!(ereg("^[0-9][0-9][0-9]$", $ccCVV)))
                    $this->errors[] = $this->language->get('error_visa_cvv');   
                break;
             case 'amex':
                if (!(ereg("^3[47][0-9]{13}$", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type'); 
                if (!(ereg("^[0-9][0-9][0-9]$", $ccCVV)))
                    $this->errors[] = $this->language->get('error_amex_cvv');   
                break;
             case 'disc':
                if (!(ereg("^6011[0-9]{12}$", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type'); 
                if (!(ereg("^[0-9][0-9][0-9]$", $ccCVV)))
                    $this->errors[] = $this->language->get('error_disc_cvv');   
                break;
             case 'diner':
                if (!(ereg("^3(0[0-5]|[68][0-9])[0-9]{11}$", $ccNumber)))
                    $this->errors[] = $this->language->get('error_cc_number_invalid_for_type'); 
                if (!(ereg("^[0-9][0-9][0-9]$", $ccCVV)))
                    $this->errors[] = $this->language->get('error_diners_cvv');   
                break;
			 default:
                break;
        }
        
        // Month must be in the range 1 to 12
        $ccMonth = (int)$ccMonth;
        if ($ccMonth < 1 || $ccMonth > 12) {
            $this->errors[] = $this->language->get('error_cc_month_invalid_range');
        }
        
        // Year cannot be more than 10 years into the future
        $ccYear = (int)$ccYear;
        $currentYear = (int)date('y');
        if ($ccYear  > $currentYear + 10) {
            $this->errors[] = $this->language->get('error_cc_year_invalid_range');
        }
        
        // Cannot expire within the next 3 days because the payment is processed on weekdays and it could be friday night
        $margin = 3;
        // $margin days before the 1st day of the month after ValidTo date on card
        $ccExpiresLimit = mktime(0,0,0, $ccMonth + 1,  1 - $margin, $ccYear);  
        $today = mktime(0,0,0);
        if ($today >= mktime(0,0,0, $ccMonth + 1,  1, $ccYear)) {
            $this->errors[] = $this->language->get('error_cc_expired');
        } else if ($today >= $ccExpiresLimit) {
            $this->errors[] = $this->language->get('error_cc_expires_too_soon');
        }
        
        return (count($this->errors) == 0);
    }  	
}
?>